package com.leenmvc.core.config.intercept;

import com.alibaba.fastjson.JSONObject;
import com.leenmvc.core.annotation.Note;
import com.leenmvc.core.security.User;
import com.leenmvc.core.security.dao.core.SysLogLoginDao;
import com.leenmvc.core.security.dao.core.SysLogOperationDao;
import com.leenmvc.core.security.entity.core.SysApi;
import com.leenmvc.core.security.entity.core.SysLogLogin;
import com.leenmvc.core.security.entity.core.SysLogOperation;
import com.leenmvc.core.utils.TipUtil;
import com.leenmvc.core.utils.dictionary.Dict;
import com.leenmvc.core.utils.http.HttpContextUtils;
import com.leenmvc.core.utils.thread.ThreadLocalManager;
import com.leenmvc.core.utils.thread.runnables.BuildApi;
import com.leenmvc.core.utils.thread.runnables.LogToDb;
import com.leenmvc.core.web.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 日志拦截器 (登录日志和操作日志)
 */
@Component
public class LogIntercept implements HandlerInterceptor {

    private final static Logger logger = LoggerFactory.getLogger(LogIntercept.class);

    @Autowired
    private SysLogOperationDao sysLogOperationDao;

    @Autowired
    private SysLogLoginDao SysLogLoginDao;

    // 目标方法执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod h = (HandlerMethod) handler;
            Method controllerMethod = h.getMethod();
            Note annotation = controllerMethod.getAnnotation(Note.class);
            if (annotation == null) {
                HttpContextUtils.returnJSON(request, response, TipUtil.getTip("LOG_INTERCEPT_REJECT"));
                return false;
            }
            String value = annotation.value();
            if (value.length() < 10) {
                HttpContextUtils.returnJSON(request, response, TipUtil.getTip("LOG_INTERCEPT_REJECT_NUM"));
                return false;
            }
            if(value.indexOf("公共方法") == -1) {
                ThreadLocalManager.put("note", value);
            }
        }
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    }

    /**
     * 执行完本次请求之后向数据库中插入登入日志和操作日志
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod h = (HandlerMethod) handler;
            Method controllerMethod = h.getMethod();
            if(Dict.bool("SYSTEM", "SAVE_LOGIN_LOG")) {
                if ("login".equals(controllerMethod.getName()) || "loginOut".equals(controllerMethod.getName())) { // 登录的相关操作
                    SysLogLogin sysLogLogin = new SysLogLogin();
                    sysLogLogin.setIp(HttpContextUtils.getIpAddr(request));
                    sysLogLogin.setCreatorName(User.getUsername());
                    Integer status = null;
                    if ("login".equals(controllerMethod.getName())) {
                        status = ThreadLocalManager.get("loginStatus") == null ? 0 : 1;
                        sysLogLogin.setStatus(status);
                    }
                    if ("loginOut".equals(controllerMethod.getName())) {
                        status = ThreadLocalManager.get("loginOutStatus") == null ? 0 : 1;
                        sysLogLogin.setStatus(status);
                    }

                    sysLogLogin.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
                    Integer operation = "login".equals(controllerMethod.getName()) ? 0 : 1;

                    sysLogLogin.setOperation(operation);
                    if (status == 1) {
                        sysLogLogin.setToken(User.getToken().getToken());
                    }
                    sysLogLogin.setCreatorName(User.getUsername());
                    sysLogLogin.setCreateDate(new Date());
                    if (!SysLogLoginDao.insert(sysLogLogin)) {
                        logger.warn("插入到登录日志表失败！IP地址为：{}", sysLogLogin.getIp());
                    }
                }
            }

            Object requestBody1 = ThreadLocalManager.get("requestBody");
            Object requestBody = requestBody1 == null ? "": requestBody1;

            String localUrl = String.valueOf(ThreadLocalManager.get("uri"));
            if (User.getUsername() != null) {
                if(Dict.bool("SYSTEM", "SAVE_OPERATION_LOG")) {
                    SysLogOperation log = new SysLogOperation();
                    log.setRequestUri(localUrl);
                    log.setIp(HttpContextUtils.getIpAddr(request));
                    log.setRequestMethod(request.getMethod());
                    log.setOperation(String.valueOf(ThreadLocalManager.get("note")));
                    log.setCreateDate(new Date());
                    log.setCreatorName(User.getUsername());
                    log.setUserAgent(request.getHeader(HttpHeaders.USER_AGENT));
                    log.setRequestParams(String.valueOf(ThreadLocalManager.get("requestParams")));
                    log.setRequestBody(requestBody);
                    log.setRequestResult(JSONObject.toJSONString((ThreadLocalManager.get("requestResult"))));
                    log.setContentType(String.valueOf(ThreadLocalManager.get("contentType")));
                    Long startTime = ThreadLocalManager.getRequestTime();
                    Long entTime = System.currentTimeMillis();
                    Integer reqTime = (int)((entTime - startTime) / 1000);
                    log.setRequestTime(reqTime);
                    log.setStatus(ThreadLocalManager.getStatusCode());
                    LogToDb.addOperation(log);
                }
                // 保存API
                if(Dict.bool("SYSTEM", "BUILD_API")) {
                    SysApi sysApi = new SysApi();
                    String url = localUrl.replaceAll("/\\d+", "/{id}").replace("//", "/");
                    sysApi.setUri(url);
                    sysApi.setOperation(String.valueOf(ThreadLocalManager.get("note")));
                    sysApi.setRequestMethod(request.getMethod());
                    sysApi.setClassName(h.getBeanType().getName());
                    sysApi.setMethodName(h.getMethod().getName());
                    sysApi.setModule(String.valueOf(ThreadLocalManager.get("module"))); // 控制器的中文表示
                    sysApi.setRequestParams(String.valueOf(ThreadLocalManager.get("requestParams")));
                    sysApi.setRequestBody(requestBody);
                    sysApi.setRequestResult((Result) ThreadLocalManager.get("requestResult"));
                    sysApi.setRequiresPermissions(String.valueOf(ThreadLocalManager.get("requiresPermissions")));
                    BuildApi.addApi(sysApi);
                }
            }
        }

        // 清空本地线程变量的全局变量HASHMAP
        ThreadLocalManager.clearGlobalVariable();
    }
}
